package com.hitqz.robot.dispatch.netty.listener;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.Cache;
import com.hitqz.robot.admin.api.dto.RequireClientLogDto;
import com.hitqz.robot.api.business.dto.CmdRobot2PosDto;
import com.hitqz.robot.api.business.dto.RobotJobDto;
import com.hitqz.robot.api.business.dto.RobotSendClientMsgDto;
import com.hitqz.robot.api.business.dto.SubscriptTopicDto;
import com.hitqz.robot.api.business.entity.JobCachesEntity;
import com.hitqz.robot.api.business.entity.RobotEntity;
import com.hitqz.robot.api.business.entity.RobotGroupEntity;
import com.hitqz.robot.api.business.entity.RobotJobEntity;
import com.hitqz.robot.api.dispatch.model.MessageDto;
import com.hitqz.robot.api.dispatch.protocol.ProtocolEnum;
import com.hitqz.robot.api.dispatch.protocol.dto.*;
import com.hitqz.robot.biz.service.JobCachesService;
import com.hitqz.robot.biz.service.RobotGroupService;
import com.hitqz.robot.biz.service.RobotJobService;
import com.hitqz.robot.biz.service.RobotService;
import com.hitqz.robot.common.core.constant.CommonConstants;
import com.hitqz.robot.common.core.util.R;
import com.hitqz.robot.dispatch.netty.ChannelCache;
import com.hitqz.robot.dispatch.netty.factory.JobAlgorithmFactory;
import com.hitqz.robot.dispatch.netty.model.DispatchJobDto;
import com.hitqz.robot.dispatch.netty.service.DispatchService;
import com.hitqz.robot.dispatch.netty.util.LockUtil;
import com.hitqz.robot.dispatch.netty.util.RobotReplyUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author xupkun
 * @date 2024/7/10
 */
@Component
@Slf4j
@AllArgsConstructor
public class Send2ClientListener {

	private final RobotJobService robotJobService;

	private final DispatchService dispatchService;

	private final RobotService robotService;

	private final JobCachesService jobCachesService;

	private final JobAlgorithmFactory jobAlgorithmFactory;

	private final RobotGroupService robotGroupService;

	/**
	 * 发送消息给客户端
	 * @param dto
	 */
	@EventListener
	@Async("serverSendThreadPool")
	public void handlerSend(RobotSendClientMsgDto dto) {
		MessageDto messageDto = new MessageDto();
		messageDto.setClientId(dto.getClientId());
		messageDto.setCmd(dto.getCmd().shortValue());
		messageDto.setSn(dto.getSeq() != null ? dto.getSeq() : 0);
		if (dto.getData() != null) {
			String data = JSONObject.toJSONString(dto.getData());
			messageDto.setData(data.getBytes(StandardCharsets.UTF_8));
		}
		ChannelCache.send2Client(dto.getClientId(), messageDto);
	}


	@EventListener
	@Async("serverSendThreadPool")
	public void handlerSend(CmdRobot2PosDto dto) {
		MessageDto messageDto= new MessageDto();
		messageDto.setSn(0);
		messageDto.setCmd(ProtocolEnum.ROBOT_NAV_POS_CMD.getCmd());
		CmdRobot2PosDto posDto = new CmdRobot2PosDto();
		posDto.setPosCode(dto.getPosCode());
		messageDto.setData(JSONObject.toJSONString(posDto).getBytes(StandardCharsets.UTF_8));
		messageDto.setClientId(dto.getClientId());
		ChannelCache.send2Client(dto.getClientId(),messageDto);
	}

	/**
	 * 修改机器人信息
	 * @param robotEntity
	 */
	@EventListener
	@Async("serverSendThreadPool")
	public void handlerRobotModel(RobotEntity robotEntity) {
		MessageDto messageDto= new MessageDto();
		messageDto.setSn(0);
		messageDto.setCmd(ProtocolEnum.ROBOT_INFO.getCmd());
		RobotDto robotDto = new RobotDto();
		BeanUtil.copyProperties(robotEntity, robotDto, false);
		messageDto.setData(JSONObject.toJSONString(robotDto).getBytes(StandardCharsets.UTF_8));
		messageDto.setClientId(robotEntity.getRobotSn());
		ChannelCache.send2Client(robotDto.getRobotSn(),messageDto);
	}
	@EventListener
	@Async("serverSendThreadPool")
	public void listenerLog(AskLogMessageDto reportLogMessageDto) {
		MessageDto messageDto= new MessageDto();
		messageDto.setSn(0);
		messageDto.setCmd(ProtocolEnum.REPORT_LOG_MESSAGE.getCmd());
		messageDto.setData(JSONObject.toJSONString(reportLogMessageDto).getBytes(StandardCharsets.UTF_8));
		messageDto.setClientId(reportLogMessageDto.getClientId());
		ChannelCache.send2Client(reportLogMessageDto.getClientId(),messageDto);
	}


	@EventListener
	@Async("serverSendThreadPool")
	public void listenerLog(RequireClientLogDto requireClientLogDto) {
		MessageDto messageDto= new MessageDto();
		messageDto.setSn(0);
		messageDto.setCmd(ProtocolEnum.UPLOAD_LOG_FILE.getCmd());
		messageDto.setData(JSONObject.toJSONString(requireClientLogDto).getBytes(StandardCharsets.UTF_8));
		messageDto.setClientId(requireClientLogDto.getClientId());
		ChannelCache.send2Client(requireClientLogDto.getClientId(),messageDto);
	}

	@EventListener
	public void handlerDoNext(RobotNextStepDto robotNextStepDto) {
		MessageDto messageDto= new MessageDto();
		messageDto.setSn(0);
		messageDto.setClientId(robotNextStepDto.getClientId());
		messageDto.setCmd(ProtocolEnum.CMD_NEXT_STEP.getCmd());
		messageDto.setData(JSONObject.toJSONString(robotNextStepDto).getBytes(StandardCharsets.UTF_8));
		ChannelCache.send2Client(robotNextStepDto.getClientId(),messageDto);
	}




	@EventListener
	@Async("serverSendThreadPool")
	public void handler(RobotJobDto robotJobDto) {
		//log.info("收到任务调度，启动任务:" + robotJobDto.getId());
		RobotJobEntity robotJobEntity = robotJobService.getById(robotJobDto.getId());
		RobotGroupEntity robotGroupEntity = robotGroupService.getById(robotJobEntity.getGroupId());
		String robotSn = robotJobDto.getClientId();
		if (StrUtil.isEmpty(robotSn)) {
			DispatchJobDto dto = jobAlgorithmFactory.getRoutingStrategy(robotGroupEntity.getJobAlgorithm()).dispatchJob(robotGroupEntity.getId());
			robotSn = dto.getClientId();
		}
		RobotEntity robotEntity = robotService.selectByRobotSn(robotSn);
		if (robotEntity == null) {
			// 缓存 等待下一次执行
			//Cache<String, LinkedList<RobotJobDto>> posInfoDtoCache = SpringUtil.getBean("taskList");
			//LinkedList<RobotJobDto> robotJobEntities = posInfoDtoCache.getIfPresent("task");
			//robotJobEntities.add(robotJobDto);
			//posInfoDtoCache.put("task", robotJobEntities);
		} else {
			Cache<Integer, RobotEntity> executeRobot = SpringUtil.getBean("executeTaskRobot");
			executeRobot.put(robotJobEntity.getId(), robotEntity);

			MessageDto messageDto= new MessageDto();
			messageDto.setSn(0);
			messageDto.setCmd(ProtocolEnum.ROBOT_CMD_TICKETS.getCmd());
			RobotCmdTicketsDto robotCmdTicketsDto = new RobotCmdTicketsDto();
			robotCmdTicketsDto.setTaskId(robotJobDto.getId());
			robotCmdTicketsDto.setTaskContent(robotJobEntity.getContent());
			robotCmdTicketsDto.setTaskName(robotJobEntity.getName());
			robotCmdTicketsDto.setClientId(robotEntity.getRobotSn());
			messageDto.setClientId(robotEntity.getRobotSn());
			messageDto.setData(JSONObject.toJSONString(robotCmdTicketsDto).getBytes(StandardCharsets.UTF_8));
			Lock lock = LockUtil.ROBOT_CMD_TICKETS_LOCKS.get(robotEntity.getRobotSn(),ProtocolEnum.ROBOT_CMD_TICKETS.getCmd() );
			if (lock == null) {
				lock = new ReentrantLock();
				LockUtil.ROBOT_CMD_TICKETS_LOCKS.put(robotEntity.getRobotSn(), ProtocolEnum.ROBOT_CMD_TICKETS.getCmd(), lock);
			}
			synchronized (lock) {
				try {
					ChannelCache.send2Client(messageDto.getClientId() ,messageDto);
					lock.wait(2000);
					R result = RobotReplyUtil.COMMON_REPLY_TABLE.get(robotEntity.getRobotSn(), ProtocolEnum.ROBOT_CMD_TICKETS.getCmd());
					if (result.getCode() == CommonConstants.FAIL) {
						//throw  new IllegalArgumentException(result.getMsg());
					}
				} catch (Exception e) {

				}
			}
		}
	}



	@EventListener
	@Async("serverSendThreadPool")
	public void handler(JobCachesEntity jobCachesEntity) {
		synchronized (jobCachesEntity.getGroupId()) {
			RobotGroupEntity robotGroupEntity = robotGroupService.getById(jobCachesEntity.getGroupId());
			DispatchJobDto dto = jobAlgorithmFactory.getRoutingStrategy(robotGroupEntity.getJobAlgorithm()).dispatchJob(robotGroupEntity.getId());
			if (dto == null) {
				return ;
			}
			if (dto.getJobId() == null) {
				log.info("重新设置任务id:" + jobCachesEntity.getId());
				dto.setJobId(jobCachesEntity.getId());
			}
			JobCachesEntity executeTask = jobCachesService.getById(dto.getJobId());
			log.info("查询缓存任务的id是: {}", JSONObject.toJSONString(executeTask));
			if (executeTask == null) {
				//
				executeTask = jobCachesEntity;
			}
            // 删除缓存任务
			RobotJobEntity robotJob =  new RobotJobEntity();
			robotJob.setCron("0 * * * * ?");
            robotJob.setName(executeTask.getTaskName() + "--时间：" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") );
			robotJob.setGroupId(executeTask.getGroupId());
			robotJob.setContent(executeTask.getTaskContent());
			robotJobService.save(robotJob);
			// 启动任务
			RobotJobDto robotJobDto = new RobotJobDto();
			robotJobDto.setId(robotJob.getId());
			robotJobDto.setClientId(dto.getClientId());
			try {
				this.handler(robotJobDto);
				jobCachesService.removeById(executeTask.getId());
			} catch (Exception e) {

			}
			SpringUtil.getApplicationContext().publishEvent(new SubscriptTopicDto("jobCaches"));
			//log.info("处理完任务缓存，启动任务:" + jobCachesEntity.getId());
		}

	}






	@EventListener
	@Async("serverSendThreadPool")
	public void handler(ModifySysInfoDto modifySysInfoDto) {
		MessageDto messageDto= new MessageDto();
		messageDto.setSn(ProtocolEnum.MODIFY_SYS_INF.getCmd());
		messageDto.setCmd(ProtocolEnum.MODIFY_SYS_INF.getCmd());
		messageDto.setData(JSONObject.toJSONString(modifySysInfoDto).getBytes(StandardCharsets.UTF_8));
		ChannelCache.send2All(messageDto);
	}

	@EventListener
	@Async("serverSendThreadPool")
	public void handlerNav(RobotCmdNavDto robotCmdNavDto) {
		log.info("下发导航状态:" + JSONObject.toJSONString(robotCmdNavDto));
		MessageDto messageDto= new MessageDto();
		messageDto.setSn(ProtocolEnum.ROBOT_NAV_CMD.getCmd());
		messageDto.setCmd(ProtocolEnum.ROBOT_NAV_CMD.getCmd());
		messageDto.setData(JSONObject.toJSONString(robotCmdNavDto).getBytes(StandardCharsets.UTF_8));
		messageDto.setClientId(robotCmdNavDto.getClientId());
		ChannelCache.send2Client(robotCmdNavDto.getClientId(), messageDto);
	}

	@EventListener
	@Async("serverSendThreadPool")
	public void handlerNav(RobotLogicOnlineDto robotCmdNavDto) {
		MessageDto messageDto= new MessageDto();
		messageDto.setSn(ProtocolEnum.ROBOT_DISPATCH_CMD.getCmd());
		messageDto.setCmd(ProtocolEnum.ROBOT_DISPATCH_CMD.getCmd());
		RobotDispatchCmdDto robotDispatchCmdDto = new RobotDispatchCmdDto();
		robotDispatchCmdDto.setLogicOnline(robotCmdNavDto.getLogicOnlineStatus());
		robotDispatchCmdDto.setClientId(robotCmdNavDto.getClientId());
		messageDto.setData(JSONObject.toJSONString(robotDispatchCmdDto).getBytes(StandardCharsets.UTF_8));
		messageDto.setClientId(robotCmdNavDto.getClientId());
		ChannelCache.send2Client(robotCmdNavDto.getClientId(), messageDto);
	}





}
